package com.bootdo.mq;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * @program: bootdo
 * @packageName: com.bootdo.mq
 * @className: RabbitMQConfig
 * @description: MQConfig
 * @author: Silver2018
 * @create: 2020-03-15 13:27
 */
@Configuration
public class RabbitMQConfig {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${spring.rabbitmq.host}")
    private String host;

    @Value("${spring.rabbitmq.port}")
    private int port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    final static String HAVING_ORDER_TO_YOU = "topic.having.order";

    // 建立一个连接容器，类型数据库的连接池,这里直接使用配置文件自动构建
    @Autowired
    private ConnectionFactory connectionFactory;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setPublisherConfirms(true);
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        return new RabbitAdmin(connectionFactory);
    }


    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate=new RabbitTemplate(connectionFactory);
        //数据转换为json存入消息队列
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    // 增加失败重试机制，发送失败之后，会尝试重发三次，重发间隔(ms)为
    // 第一次 initialInterval
    // 此后: initialInterval * multiplier > maxInterval ? maxInterval : initialInterval * multiplier
    // 配合集群使用的时候, 当mq集群中一个down掉之后,重试机制尝试其他可用的mq
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
        exponentialBackOffPolicy.setInitialInterval(500);
        exponentialBackOffPolicy.setMaxInterval(5000);
        exponentialBackOffPolicy.setMultiplier(10.0);
        retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);
        return retryTemplate;
    }


    // RabbitMQ的使用入口,未指定任务queue等信道信息,默认模板
    @Bean(name = "rabbitTemplate")
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, RetryTemplate retryTemplate) {
        logger.info("init normal template, if not set info, will use it.");
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setReplyTimeout(600000);
        rabbitTemplate.setRetryTemplate(retryTemplate);
        //数据转换为json存入消息队列
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    @Bean("customContainerFactory")
    public SimpleRabbitListenerContainerFactory containerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConcurrentConsumers(20);
        factory.setMaxConcurrentConsumers(20);
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    @Bean
    public Queue queueHavingOrder() {
        return new Queue(RabbitMQConfig.HAVING_ORDER_TO_YOU,true);
    }

    @Bean
    TopicExchange exchange() {
        return new TopicExchange("exchange",true,false);
    }

    @Bean
    Binding bindingExchangeHavingOrderInfo(Queue queueHavingOrder, TopicExchange exchange) {
        return BindingBuilder.bind(queueHavingOrder).to(exchange).with(HAVING_ORDER_TO_YOU);
    }

}
